package cn.tedu.luban.order.main.service;

import cn.tedu.luban.attach.api.AttachApi;
import cn.tedu.luban.attach.protocol.dto.AttachDTO;
import cn.tedu.luban.attach.protocol.param.AttachUpdateParam;
import cn.tedu.luban.attach.protocol.query.AttachQuery;
import cn.tedu.luban.demand.api.DemandApi;
import cn.tedu.luban.order.common.enums.OrderResultEnum;
import cn.tedu.luban.order.common.enums.OrderStatusEnum;
import cn.tedu.luban.order.main.converter.OrderLogConverter;
import cn.tedu.luban.order.main.repository.OrderLogRepository;
import cn.tedu.luban.order.main.repository.OrderRepository;
import cn.tedu.luban.order.protocol.bo.AttachInfoBO;
import cn.tedu.luban.order.protocol.bo.OrderBO;
import cn.tedu.luban.order.protocol.bo.OrderLogBO;
import cn.tedu.luban.order.protocol.dto.OrderMessageDTO;
import cn.tedu.luban.order.protocol.param.*;
import cn.tedu.luban.order.protocol.query.FrontOrderListQuery;
import cn.tedu.luban.passport.protocol.jwt.UserPrinciple;
import cn.tedu.luban.passport.sdk.security.LubanSecurityContext;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;
import com.tedu.inn.protocol.ListRecordTotalBO;
import com.tedu.inn.protocol.exception.BusinessException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.bouncycastle.cms.PasswordRecipientId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
@Slf4j
public class OrderService {

    @Autowired
    private DemandApi demandApi;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private OrderLogRepository orderLogRepository;

    @Autowired
    private OrderLogConverter orderLogConverter;


    @Autowired
    private MessageService messageService;

    public String orderCreate(OrderCreateParam orderCreateParam) throws BusinessException {
        //1.RPC远程调用 抢单 传递一个需求单编号
        Boolean grabOrder = demandApi.grabOrder(orderCreateParam.getRequestOrderNo());

        if (!grabOrder) {
            throw new BusinessException(OrderResultEnum.ORDER_GRAB_FAIL);
        }
        //抢单成功，创建生成订单
        replenishOrder(orderCreateParam);
        orderRepository.saveOrder(orderCreateParam);

        //对于抢单成功的订单创建操作日志，新增表order_log
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                orderCreateParam.getUserId(),
                orderCreateParam.getOrderNo(),
                OrderStatusEnum.ORDER_CREATE_SUCCESS
        );
        orderLogRepository.saveOrderLog(orderLogParam);
        //发送一个延迟消息，处理超时订单，消息所携带的数据，只需要一个订单编号
        messageService.sendDelayMessage(orderCreateParam.getOrderNo());

        return orderCreateParam.getOrderNo();
    }

    private void replenishOrder(OrderCreateParam orderCreateParam) throws BusinessException {
        //1.userId
        Long userId = getUserId();
        orderCreateParam.setUserId(userId);
        //2.orderNo
        String orderNO = UUID.randomUUID().toString();
        orderCreateParam.setOrderNo(orderNO);
        //3.status,抢单成功，状态为10
        Integer status = OrderStatusEnum.ORDER_CREATE_SUCCESS.getStatus();
        orderCreateParam.setStatus(status);
    }

    private Long getUserId() throws BusinessException {
        UserPrinciple loginToken = LubanSecurityContext.getLoginToken();
        if (loginToken == null) {
            throw new BusinessException(OrderResultEnum.USER_TOKEN_VERIFY_FAILED);
        }
        return loginToken.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    public void orderDelay(String orderNo) throws BusinessException {
        //1.查询订单，判断订单是否存在，存在则继续，不存在则抛出异常
        OrderBO orderBO = checkEmptyOrder(orderNo);
        //2.检查订单状态
        Integer currentStatus = orderBO.getStatus();
        if (currentStatus == OrderStatusEnum.ORDER_CREATE_SUCCESS.getStatus()) {
            //超时未签到
            //验证当前订单状态和想要修改的状态是否匹配 当前状态是10 目标状态是-30
            Integer targetStatus = OrderStatusEnum.CANCELLED_BY_EXPIRE.getStatus();
            checkStatusTransfer(currentStatus, targetStatus);
            //关闭订单、更新订单状态
            OrderParam orderParam = new OrderParam();
            orderParam.setStatus(OrderStatusEnum.CANCELLED_BY_EXPIRE.getStatus());
            orderParam.setOrderNo(orderBO.getOrderNo());
            orderRepository.updateStatus(orderParam);
            //记录关闭日志
            OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                    999L,
                    orderBO.getOrderNo(),
                    OrderStatusEnum.CANCELLED_BY_EXPIRE
            );
            orderLogRepository.saveOrderLog(orderLogParam);
            //归还需求单
            Boolean returnOrder = demandApi.returnOrder(orderBO.getRequestOrderNo());

            if (!returnOrder) {
                throw new BusinessException("9002", "归还需求单失败");
            }
        }

    }

    private static Map<Integer, List<Integer>> register;

    static {
        //初始化注册器
        register = new HashMap<>();
        //Integer key值，记录的是所有流转状态的currentStatus ,例如是10
        //List<Integer> value，表示key的状态能够流转的targetStatus
        //10：抢单成功  20：签到  30：服务完成待结算  40：完成订单    50：施工图片确认   -10:用户关闭    -20：平台关闭    -30：超时关闭
        register.put(10, Arrays.asList(20, -30, -20, -10));
        register.put(20, Arrays.asList(50));
        register.put(50, Arrays.asList(50, 30));
        register.put(30, Arrays.asList(40));

    }

    @SneakyThrows
    private void checkStatusTransfer(Integer currentStatus, Integer targetStatus) throws BusinessException {
        //注册器
        if (register.containsKey(currentStatus) && register.get(currentStatus).contains(targetStatus))
            return;

        throw new BusinessException("7001", "订单流转状态错误");

    }

    private OrderBO checkEmptyOrder(String orderNo) throws BusinessException {
        //使用订单编号，调用仓储层，查询订单
        OrderBO orderBO = orderRepository.getOrderByOrderNo(orderNo);
        if (orderBO == null || orderBO.getId() == null) {
            throw new BusinessException(OrderResultEnum.ORDER_EMPTY);
        }
        return orderBO;
    }

    public ListRecordTotalBO<OrderBO> orderList(FrontOrderListQuery frontOrderListQuery) throws BusinessException {
        //1.查询total
        frontOrderListQuery.setUserId(getUserId());
        Long total = orderRepository.countOrders(frontOrderListQuery);
        //2.判断条数
        log.info("frontOrderListQuery：{}",frontOrderListQuery);
        ListRecordTotalBO<OrderBO> totalBO=null;
        if (total==0){
            totalBO=new  ListRecordTotalBO<OrderBO>(null,total);
        }else {
            //3.查询对应条件的list
            List<OrderBO> orderBOS = orderRepository.queryOrders(frontOrderListQuery);
            totalBO=new  ListRecordTotalBO<OrderBO>(orderBOS,total);
        }
        return totalBO;
    }

    public OrderBO orderInfo(String orderNo) throws BusinessException {
        //1.检查并读取非空的订单
        OrderBO orderBO = checkEmptyOrder(orderNo);
        //2.根据订单编号查询对应的日志记录，一个订单对应多个日志
        List<OrderLogBO> orderLogBOS = orderLogRepository.getOrderLogByOrderNo(orderNo);
        if (CollectionUtils.isEmpty(orderLogBOS)){
            throw new BusinessException("5000","订单日志记录异常");
        }

        for (OrderLogBO orderLogBO : orderLogBOS) {
            //订单日志记录 operateName==签到   operate_time==signTime
            if ("签到".equals(orderLogBO.getOperateName())){
                orderBO.setSignTime(orderLogBO.getOperateTime());
            }

            //订单日志记录 operateName==完成订单   operate_time==finishTime
            if ("完成订单".equals(orderLogBO.getOperateName())){
                orderBO.setFinishTime(orderLogBO.getOperateTime());
            }
        }
        //远程调用 获取绑定施工图片
        putAttachUrls(orderBO);
        return orderBO;
    }

    private void putAttachUrls(OrderBO orderBO) {
        //根据订单ID 以及 定义的业务类型  获取图片
        Integer bizId=orderBO.getId().intValue();
        Integer bizType=200;
        AttachQuery attachQuery = new AttachQuery();
        attachQuery.setBusinessId(bizId);
        attachQuery.setBusinessType(bizType);
        List<AttachDTO> attachDTOS = attachApi.getAttachInfoByParam(attachQuery);
        //封装每个图片的url地址，需要遍历循环attachDTOS
        ArrayList<AttachInfoBO> attachInfoBOS = new ArrayList<>();
        for (AttachDTO attachDTO : attachDTOS) {
            String url="http://localhost:8092/static/"+attachDTO.getFileUuid();
            AttachInfoBO attachInfoBO = new AttachInfoBO();
            attachInfoBO.setUrl(url);
            attachInfoBOS.add(attachInfoBO);
        }
        orderBO.setAttachInfoBO(attachInfoBOS);
    }

    public void orderSign(OrderSignParam orderSignParam) throws BusinessException {
        //1.检查订单是否为空
        String orderNo = orderSignParam.getOrderNo();
        OrderBO orderBO = checkEmptyOrder(orderNo);
        //2.检查当前订单状态 是否满足流转状态
        checkStatusTransfer(orderBO.getStatus(),OrderStatusEnum.ORDER_SIGN_SUCCESS.getStatus());
        //3.更新订单状态
        OrderParam orderParam = new OrderParam();
        orderParam.setStatus(OrderStatusEnum.ORDER_SIGN_SUCCESS.getStatus());
        orderParam.setOrderNo(orderNo);
        orderRepository.updateStatus(orderParam);
        //4.记录订单操作日志
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                getUserId(),
                orderNo,
                OrderStatusEnum.ORDER_SIGN_SUCCESS
        );

        orderLogRepository.saveOrderLog(orderLogParam);
    }

    @Transactional(rollbackFor = Exception.class)
    public void orderConfirm(OrderConfirmParam orderConfirmParam) throws BusinessException {
        //1.验证param中的ids图片数据是否为空，如果为空则抛出异常
        List<Long> attachIds = orderConfirmParam.getAttachIds();
        if (CollectionUtils.isEmpty(attachIds)){
            throw new BusinessException("7000","图片数据为空，无法确认施工");
        }
        //2.检查订单是否存在
        OrderBO orderBO = checkEmptyOrder(orderConfirmParam.getOrderNo());
        //3.检查状态流转
        checkStatusTransfer(orderBO.getStatus(), OrderStatusEnum.ORDER_ATTACH_CONFIRM.getStatus());
        //4.拿到订单状态，判断是否为施工上传，来决定是否调用状态更新
        if (orderBO.getStatus()!=OrderStatusEnum.ORDER_ATTACH_CONFIRM.getStatus()){
            OrderParam orderParam = new OrderParam();
            orderParam.setStatus(OrderStatusEnum.ORDER_ATTACH_CONFIRM.getStatus());
            orderParam.setOrderNo(orderBO.getOrderNo());
            orderRepository.updateStatus(orderParam);
        }
        //5.日志记录
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                getUserId(),
                orderBO.getOrderNo(),
                OrderStatusEnum.ORDER_ATTACH_CONFIRM
        );
        orderLogRepository.saveOrderLog(orderLogParam);
        //6.图片绑定
        bindPicture(orderConfirmParam,200,orderBO.getId());
    }

    @Autowired
    private AttachApi attachApi;

    private void bindPicture(OrderConfirmParam orderConfirmParam, int bizType, Long bizId) {
        //组织入参
        ArrayList<AttachUpdateParam> attachUpdateParams = new ArrayList<>();
        for (Long attachId : orderConfirmParam.getAttachIds()) {
            AttachUpdateParam attachUpdateParam = new AttachUpdateParam();
            attachUpdateParam.setId(attachId.intValue());
            attachUpdateParam.setIsCover(1);
            attachUpdateParam.setBusinessType(bizType);
            attachUpdateParam.setBusinessId(bizId.intValue());
            attachUpdateParams.add(attachUpdateParam);
        }
        attachApi.batchUpdateAttachByIdList(attachUpdateParams);
    }

    public void orderFinish(OrderFinishParam orderFinishParam) throws BusinessException {
        //1.检查订单是否存在
        OrderBO orderBO = checkEmptyOrder(orderFinishParam.getOrderNo());
        //2.使用订单状态 判断目标状态是否合法
        checkStatusTransfer(orderBO.getStatus(),OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE.getStatus());
        //3.更新订单状态  更新为完成待结算
        OrderParam orderParam = new OrderParam();
        orderParam.setStatus(OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE.getStatus());
        orderParam.setOrderNo(orderFinishParam.getOrderNo());
        orderRepository.updateStatus(orderParam);
        //4.记录日志
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                getUserId(),
                orderFinishParam.getOrderNo(),
                OrderStatusEnum.ORDER_SERVICE_SUCCESS_UN_SETTLE
        );
        orderLogRepository.saveOrderLog(orderLogParam);
        //5.发送消息  settle 要计算账单，需要价钱数据 分润 订单 需求单 师傅id 平台id
        OrderMessageDTO orderMessageDTO = new OrderMessageDTO();
        BeanUtils.copyProperties(orderBO,orderMessageDTO);
        messageService.sendFinishMessage(orderMessageDTO);


    }

    public void orderComplete(String orderNo) throws BusinessException {
        //1.使用订单编号，查询订单，判断是否为空
        OrderBO orderBO = checkEmptyOrder(orderNo);
        //2.判断状态流转异常
        checkStatusTransfer(orderBO.getStatus(),OrderStatusEnum.ORDER_FINISH.getStatus());
        //3.更新订单状态  更新为完成
        OrderParam orderParam = new OrderParam();
        orderParam.setStatus(OrderStatusEnum.ORDER_FINISH.getStatus());
        orderParam.setOrderNo(orderNo);
        orderRepository.updateStatus(orderParam);
        //4.记录日志
        OrderLogParam orderLogParam = orderLogConverter.assembleOrderLogParam(
                999l,
                orderNo,
                OrderStatusEnum.ORDER_FINISH
        );
        orderLogRepository.saveOrderLog(orderLogParam);
    }
}
